#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>

#include "Gui.h"
#include "Gfx.h"

#include <eastl/string.h>

typedef bool(*DoLayoutFunc)(GUILayout*,float&,float&,float&,float&);

eastl::map<eastl::string, Pic> ButtonImages;

///************************************************************************/
/// GUIState
///************************************************************************/

struct GUIState
{
	float MouseX;
	float MouseY;
	int MouseB;

	ID HotItem;
	ID ActiveItem;

	Fnt Font;

#define MAX_LAYOUTS 32
	GUILayout Layouts[MAX_LAYOUTS];
	int LayoutTop;

	GUILayout* PushLayout(int type, DoLayoutFunc func, float x, float y, float w, float h, const Color& bgcolor)
	{
		assert(LayoutTop<31);
		GUILayout* layout = &Layouts[LayoutTop++];
		layout->Type = type;
		layout->DoFunc = func;
		layout->X = x;
		layout->Y = y;
		layout->W = w;
		layout->H = h;
		layout->Enabled = true;
		layout->BGColor = bgcolor;
		DoLayout(*layout);
		return layout;
	}
	void PopLayout()
	{
		assert(LayoutTop);
		LayoutTop--;
	}
	bool DoLayout(GUILayout& layout)
	{
		return DoLayout(layout.X, layout.Y, layout.W, layout.H);
	}
	bool DoLayout(float& x, float& y, float& w, float& h)
	{
		if (!LayoutTop) return true;

		return Layouts[LayoutTop-1].DoFunc(&Layouts[LayoutTop-1], x, y, w, h);
	}
} 
UIState;

///************************************************************************/
/// System
///************************************************************************/

void Input_UpdateGUIState(float x, float y, int mb)
{
	UIState.MouseX = x;
	UIState.MouseY = y;
	UIState.MouseB = mb;
}

void Input_GUIBegin()
{
	if (!UIState.Font)
		UIState.Font = LoadFnt("Data/font.ttf", 16);
	UIState.HotItem = 0;
	UIState.LayoutTop = 0;
}

void Input_GUIEnd()
{
	if (UIState.MouseB == 0)
	{
		UIState.ActiveItem = 0;
	}
	else
	{
		if (UIState.ActiveItem == 0)
			UIState.ActiveItem = -1;
	}
}

///************************************************************************/
/// Utils
///************************************************************************/

inline const ALLEGRO_COLOR& ToColor(const Color& col)
{
	return *(ALLEGRO_COLOR*)&col;
}

bool IsInside(float x, float y, float w, float h)
{
	return !(UIState.MouseX < x || UIState.MouseY < y || UIState.MouseX >= x + w || UIState.MouseY >= y + h);
}

///************************************************************************/
/// Widgets
///************************************************************************/

bool Button(ID id, float x, float y, const char* text, float w, float h, const Color& bcolor, int flags)
{
	bool enabled = UIState.DoLayout(x,y,w,h);

	// Check whether the button should be hot
	if (enabled && IsInside(x, y, w, h))
	{
		UIState.HotItem = id;
		if (UIState.ActiveItem == 0 && (UIState.MouseB & 1))
			UIState.ActiveItem = id;
	}

	DrawFilledRect(x+4, y+4, w, h, bcolor*0.25f);
	Color cl = bcolor;
	if (UIState.HotItem == id && enabled && !(flags & GUIFLAG_Disabled))
	{
		if (UIState.ActiveItem == id)
		{
			// Button is active and hot
			x += 2;
			y += 2;
		}
		else
		{
			// Button is merely 'hot'

			y -= 2;
			x -= 2;
		}
	}
	else // button is not hot, but it may be active
	{
		//cl = bcolor*0.75f;
	}

	DrawFilledRect(x, y, w, h, cl);

	if (*text == '@')
	{
		text++;
		if (*text != '@')
		{
			Pic pic = ButtonImages[text];
			DrawPic(pic, x+(w/2-PicWidth(pic)/2), y+(h/2-PicHeight(pic)/2));
			text = 0;
		}
	}

	if (text)
	{
		int len = TextLength(UIState.Font, text);
		DrawFnt(UIState.Font, x+(w/2-len/2), y+(h/2-FntHeight(UIState.Font)/2), (flags & GUIFLAG_Disabled)?Color::Black(0.5f):Color::Black(), text);
	}
	

	if (enabled &&
		UIState.MouseB == 0 && 
		UIState.HotItem == id && 
		UIState.ActiveItem == id)
	{
		return true;
	}

	return false;
}

///************************************************************************/
/// Layouts
///************************************************************************/

bool GFStaticLayout(GUILayout* layout, float& x, float& y, float& w, float& h)
{
	x += layout->X;
	y += layout->Y;
	return layout->Enabled;
}

GUILayout* PushStaticLayout(float x, float y, float w, float h, const Color& bgcolor)
{
	GUILayout* ly = UIState.PushLayout('STAT', GFStaticLayout, x,y,w,h,bgcolor);
	DrawFilledRect(ly->X, ly->Y, ly->W, ly->H, bgcolor);
	return ly;
}

void PopLayout()
{
	UIState.PopLayout();
}

void SetGUIFont( Fnt font )
{
	UIState.Font = font;
}

ID GetGUIHotItem()
{
	return UIState.HotItem;
}